package com.cloud.zk;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

//@Component
public class ZookeeperClient {

    public final CuratorFramework client;

    // 分布式锁
    private static InterProcessMutex lock;
    private static final String LOCK_PATH = "/my_lock";

    public ZookeeperClient() {
        client = CuratorFrameworkFactory.newClient(
                "localhost:2181",
                new ExponentialBackoffRetry(1000, 3)
        );
        client.start();
        lock = new InterProcessMutex(client, LOCK_PATH);
    }

    /**
     * 获取分布式锁
     */
    public static boolean acquireLock() throws Exception {
        return lock.acquire(10, TimeUnit.SECONDS);
    }

    /**
     * 释放锁
     */
    public static void releaseLock() throws Exception {
        if (lock.isAcquiredInThisProcess()) {
            lock.release();
        }
    }

    /**
     * 创建节点（如果不存在的话）
     */
    public void createNode(String path, String data) throws Exception {
        // 检查路径是否已存在
        if (client.checkExists().forPath(path) == null) {
            // 创建节点，并存储数据
            client.create().creatingParentsIfNeeded().forPath(path, data.getBytes(StandardCharsets.UTF_8));
            System.out.println("节点 " + path + " 创建成功");
        } else {
            System.out.println("节点 " + path + " 已存在");
        }
    }

    /**
     * 创建临时节点（Ephemeral Node）
     * 临时节点会在客户端会话断开时自动删除
     */
    public void createEphemeralNode(String path, String data) throws Exception {
        // 使用 CreateMode.EPHEMERAL 来创建临时节点
        client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path, data.getBytes(StandardCharsets.UTF_8));
        System.out.println("临时节点 " + path + " 创建成功");
    }

    /**
     * 创建顺序节点（Sequential Node）
     * 顺序节点在名称后自动加上递增的数字后缀
     */
    public void createSequentialNode(String path, String data) throws Exception {
        // 使用 CreateMode.PERSISTENT_SEQUENTIAL 来创建顺序节点
        String createdPath = client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT_SEQUENTIAL)
                .forPath(path, data.getBytes(StandardCharsets.UTF_8));
        System.out.println("顺序节点 " + createdPath + " 创建成功");
    }

    /**
     * 获取节点的数据
     */
    public String getData(String path) throws Exception {
        byte[] bytes = client.getData().forPath(path);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /**
     * 设置节点的数据
     */
    public void setData(String path, String data) throws Exception {
        client.setData().forPath(path, data.getBytes(StandardCharsets.UTF_8));
        System.out.println("节点 " + path + " 数据更新为: " + data);
    }

    /**
     * 删除节点
     */
    public void deleteNode(String path) throws Exception {
        try {
            client.delete().forPath(path);
            System.out.println("节点 " + path + " 删除成功");
        } catch (KeeperException.NoNodeException e) {
            System.out.println("节点 " + path + " 不存在，删除失败");
        }
    }

    /**
     * 判断节点是否存在
     */
    public boolean exists(String path) throws Exception {
        return client.checkExists().forPath(path) != null;
    }

    /**
     * 获取Zookeeper客户端
     */
    public CuratorFramework getClient() {
        return client;
    }

    /**
     * 关闭Zookeeper客户端
     */
    public void close() {
        if (client != null) {
            client.close();
        }
    }

    /**
     * 添加子节点监听器
     */
    public void addWatch(String path) throws Exception {
        // 创建 PathChildrenCache 对象，用来监听路径的子节点变化
        PathChildrenCache cache = new PathChildrenCache(client, path, true);

        // 添加监听器，监听子节点变化事件
        cache.getListenable().addListener((client, event) -> {
            // 打印事件类型和路径
            System.out.println("Event: " + event.getType() + " on path: " + path);

            // 可以根据 event.getType() 判断事件类型
            switch (event.getType()) {
                case CHILD_ADDED:
                    System.out.println("watch子节点添加: " + event.getData().getPath());
                    break;
                case CHILD_UPDATED:
                    System.out.println("watch子节点更新: " + event.getData().getPath());
                    break;
                case CHILD_REMOVED:
                    System.out.println("watch子节点删除: " + event.getData().getPath());
                    break;
                case CONNECTION_RECONNECTED:
                    System.out.println("watch连接重新建立");
                    break;
                default:
                    break;
            }
        });

        // 启动监听器
        cache.start();
    }
}
